<!-- 中间编辑面板 -->
<template>
    <div class="designer-panel">
        <div class="designer-panel-body" id="center-panel">
            <!-- 画布 -->
            <draggable tag="div" :list="pageTemplate.children" class="edit-panel" id="edit-panel"
                :style="pageTemplate.componentProps.style" @click="handleClickEditPanel" v-bind="dragOption"
                @add="addComponent" @start="dragStart($event, props.pageTemplate.children)"
                @end="dragEnd($event, props.pageTemplate.children)">
                <template #item="{ element,index }">
                    <componentWrap v-if="element.id != undefined" :item="element" @dragStart="dragStart"
                        @mousedown="handleMouseDown($event, element)" @dragEnd="dragEnd"
                        @addChildComponent="addChildComponent" :selectItem="selectItem"
                        @clearOtherActive="clearOtherActive" @copyComponent="copyComponent"
                        @deleteComponent="deleteComponent" @handleSetSelectItem="handleSetSelectItem" :key="element.id">
                    </componentWrap>
                </template>
            </draggable>
            <!-- TODO 全局统一拖拽选中框 -->
            <!-- <div class="active-box" ref="activeBox"></div> -->
        </div>
    </div>
</template>

<script setup>
import { ref, reactive, watch , defineProps, createVNode } from 'vue'
import draggable from "vuedraggable";
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import { getPrimaryId, globalOptions, storage, pageData } from '../../pageManager.js'
import { revoke } from '../../common/util/revoke.js'
import { cloneObject } from '../../common/util/util.js'

const emit = defineEmits(['handleSetSelectItem', 'clearActiveItem', 'clearOtherActive', 'handleResetSelectItem', 'resetEditPanel'])

const activeBox = ref(null);

const props = defineProps({
    pageTemplate: {
        type: Object,
        required: true
    },
    // 缩放的值
    scaleValue: {
        type: Number,
        default: 1
    },
    // 选中的组件
    selectItem: {
        type: Object,
    }
})

let dragOption = reactive({
    group: { name: 'form-draggable' },
    ghostClass: 'moving',
    animation: 180,
    handle: '',
})

// 监听数据的变化
watch(() => storage.pageType, (newValue, oldValue) => {
    if (newValue == "pc") {
        props.pageTemplate.componentProps.style.width = '100%';
    } else if (newValue == "ipad") {
        props.pageTemplate.componentProps.style.width = '800px';
    } else if (newValue == 'mobile') {
        props.pageTemplate.componentProps.style.width = '420px'
    }
})

/**
 * @method
 * @param {Object} evt 当前拖拽的对象实例
 * @desc 往中间面板添加组件
 */
const addComponent = (evt) => {
    // console.log("addComponent");
    // alert("往中间面板添加组件")
    let newIndex = evt.newIndex;
    // 深度拷贝
    const listString = JSON.stringify(props.pageTemplate.children);
    props.pageTemplate.children = JSON.parse(listString);

    let currentItem = props.pageTemplate.children[newIndex];
    currentItem.active = true;

    // 生成唯一的ID值
    let id = currentItem.type + "_" + getPrimaryId();;

    // 判断是否已设置过id
    if (currentItem.id == undefined || currentItem.id == "" || currentItem.id == null) {
        // 赋值ID
        currentItem.id = id;
    }

    // 判断是否已设置字段名
    let field = currentItem.field;
    if (field == undefined || field == "" || field == null) {
        currentItem.field = id;
    }

    // 如果之前是表单组件
    if (currentItem.isFormItem) {
        currentItem.isFormItem = false;
        delete currentItem.isFormItem;
        delete currentItem.formId;
    }

    // 如果是表单容器组件
    if (currentItem.type == 'form') {
        pageData[id] = {};
    }

    emit("clearOtherActive", id)
    // 添加组件后选中当前组件
    emit("handleSetSelectItem", props.pageTemplate.children[newIndex]);
    revoke.add(props.pageTemplate, `添加【${currentItem.name}】组件`)
}


/**
 * @method
 * @param {Object} evt 当前拖拽的对象实例
 * @desc 往中间组件添加子组件
 */
const addChildComponent = (evt, item) => {
    let newIndex = evt.newIndex;
    let id = item.children[newIndex].type + "_" + getPrimaryId();

    const listString = JSON.stringify(item.children);
    item.children = JSON.parse(listString);

    let childItem = item.children[newIndex];
    childItem.active = true;


    // 单独处理表单组件
    // 如果是表单组件，子组件则添加表单属性
    if (item.type != 'form') {
        childItem.isFormItem = false;
        childItem.formId = "";
        delete childItem.isFormItem;
        delete childItem.formId;
    }

    // 判断是否已设置过id
    if (childItem.id == undefined || childItem.id == "" || childItem.id == null) {
        // 赋值ID
        childItem.id = id;
    }

    // 判断是否已设置过字段
    let field = childItem.field;
    if (field == undefined || field == "" || field == null) {
        childItem.field = id;
    }

    // 如果是自由布局，则设置默认值
    if (childItem.layoutType == 'free') {
        childItem.x = 0;
        childItem.y = 0;
    }

    emit("clearOtherActive", id)
    // 添加组件后选中当前组件
    emit("handleSetSelectItem", childItem);

    revoke.add(props.pageTemplate, `往【${item.name}】组件中添加【${childItem.name}】子组件`)
}

/**
 * @method
 * @param {Object} item 当前组件的对象数据
 * @desc 复制组件
 */
const copyComponent = (item, event) => {
    let isCopy = true;
    let newItem = {};

    // 阻止默认行为
    event.stopPropagation();

    const traverse = array => {
        array.forEach((element, index) => {
            if (element.id === item.id) {
                if (isCopy) {
                    // 复制添加到选择节点后面
                    newItem = cloneObject(element);
                    array.splice(index + 1, 0, newItem);
                }
                // 复制完成，重置id值
                handleCopyOk(array, index + 1);
                return;
            } else {
                if (element.children && element.children.length > 0) {
                    traverse(element.children);
                }
            }
        });
    };
    traverse(props.pageTemplate.children);
    revoke.add(props.pageTemplate, `复制【${item.name}】组件`)
}

/**
 * @method
 * @param {Array} array 组件数组
 * @param {Number} index 当前索引
 * @desc 复制组件成功后的操作
 */
const handleCopyOk = (array, newIndex) => {
    let newItem = array[newIndex];
    // let id = newItem.type + "_" + new Date().getTime();
    let id = newItem.type + "_" + getPrimaryId();
    newItem.id = id;
    newItem.field = id;
    newItem.active = true;

    // 如果存在子组件则重置其ID值
    if (newItem.children && newItem.children.length > 0) {
        // alert("存在子组件")
        const listString = JSON.stringify(newItem.children);
        newItem.children = JSON.parse(listString);
        resetChildrenItemId(newItem.children);
    }

    emit("handleSetSelectItem", newItem);
}

/**
 * @method
 * @param {Object} data 子组件数据
 * @desc 重置子组件ID值
 */
const resetChildrenItemId = (data) => {
    // console.log("子组件数据：", data);
    for (let i = 0; i < data.length; i++) {
        let item = data[i];
        let id = item.type + "_" + getPrimaryId();
        item.id = id;
        if (item.children && item.children.length > 0) {
            const listString = JSON.stringify(item.children);
            item.children = JSON.parse(listString);
            resetChildrenItemId(item.children);
        }
    }
}


/**
 * @method
 * @param {Object} item 当前组件的对象数据
 * @desc 删除组件
 */
const deleteComponent = (item, event) => {
    // 阻止默认行为
    event.stopPropagation();

    const traverse = array => {
        array = array.filter((element, index) => {
            // 针对子组件做操作
            if (element.children && element.children.length > 0) {
                element.children = traverse(element.children);
            }
            if (element.id !== item.id) {
                return true;
            } else {
                if (array.length === 1) {
                    emit("handleSetSelectItem", array[0])
                } else if (array.length - 1 > index) {
                    emit("handleSetSelectItem", array[index + 1])
                } else {
                    emit("handleSetSelectItem", array[index - 1])
                }
                return false;
            }
        });
        return array;
    };


    if (globalOptions.deleteConfirm) {
        Modal.confirm({
            title: `确定要删除【${item.name}】组件吗?`,
            icon: createVNode(ExclamationCircleOutlined),
            cancelText: "取消",
            okText: "确认",
            // content: createVNode('div', { style: 'color:red;font-size:12px' }, '此操作将不可撤销'),
            onOk() {
                props.pageTemplate.children = traverse(props.pageTemplate.children);
                if (props.pageTemplate.children.length < 1) {
                    emit('resetEditPanel');
                }
                message.success(`删除【${item.name}】组件成功`);
                revoke.add(props.pageTemplate, `删除【${item.name}】组件`)
            },
            onCancel() {
            },
        });
    } else {
        props.pageTemplate.children = traverse(props.pageTemplate.children);
        if (props.pageTemplate.children.length < 1) {
            emit('resetEditPanel');
        }
        message.success(`删除【${item.name}】组件成功`);
        revoke.add(props.pageTemplate, `删除【${item.name}】组件`)
    }




}

/**
 * @method
 * @param {Object} item 当前组件的对象数据
 * @desc 选中组件，将值传递至顶层dcPageDesigner中的handleSetSelectItem函数中
 */
const handleSetSelectItem = (item) => {
    // setActiveBox(item);
    emit("handleSetSelectItem", item);
}

const setActiveBox = (item) => {
    // 获取中间编辑面板
    let editPanelRect = document.getElementById('center-panel').getBoundingClientRect();
    let itemEvtRect = document.getElementById(item.id).getBoundingClientRect();


    // console.log("当前元素：", item)
    // console.log("当前元素Rect：", itemEvtRect);

    activeBox.value.style.top = itemEvtRect.top - editPanelRect.top + 'px';
    activeBox.value.style.left = itemEvtRect.left - editPanelRect.left + 'px';

    activeBox.value.style.width = itemEvtRect.width + 'px';
    activeBox.value.style.height = itemEvtRect.height + 'px';
}



let currentDragItem = null,  // 当前拖拽的组件对象
    currentMouseLeft = 0,    // 当前鼠标 X 位置
    currentMouseTop = 0;     // 当前鼠标 Y 位置

/**
* @method
* @param {Object} evt 当前拖拽的对象实例
* @param {Array} list 当前组件list
* @desc 拖拽开始时
*/
const dragStart = (evt, list) => {

    let item = list[evt.oldIndex];

    currentDragItem = item;

    // 拖拽结束,自动选择拖拽的控件项
    emit("handleSetSelectItem", list[evt.oldIndex]);
}

/**
 * @method
 * @param {*} evt 
 * @desc 拖拽结束时
 */
const dragEnd = (evt) => {


    // console.log("拖拽结束：", evt);

    let item = currentDragItem;

    // 组件为自由拖动类型时才会触发
    if (item.layoutType == 'free') {

        let originalEvent = evt.originalEvent;

        // 获取中间编辑面板
        let editPanelRect = document.getElementById('center-panel').getBoundingClientRect();
        // 当前元素
        let currentItemRect = document.getElementById(item.id).getBoundingClientRect();

        // 原始计算出的x、y坐标（元素当前位置并减去面板距离再减去鼠标按下时的位置）
        let originalX = originalEvent.clientX - editPanelRect.left - currentMouseLeft;
        let originalY = originalEvent.clientY - editPanelRect.top - currentMouseTop;

        // 处理 X、Y轴的边界检查，确保元素不会超出面板
        // x轴的值不能小于0，并且不能大于面板的宽度
        // y轴的值不能小于0，可以大于面板的高度，因为可能需要滚动
        item.x = Math.max(0, Math.min(originalX, editPanelRect.width - currentItemRect.width));
        item.y = Math.max(0, originalY);

        revoke.add(props.pageTemplate, `拖动了【${item.name}】组件的位置`)

    } else if (item.layoutType == "flow") {

        // 如果新老下标不相等则代表位置发生了变动
        if(evt.newIndex != evt.oldIndex){
            revoke.add(props.pageTemplate, `拖动了【${item.name}】组件的位置`)
        }
    }


    // 拖动结束后清空鼠标暂存的位置
    currentMouseLeft = 0;
    currentMouseTop = 0;
}

/**
 * 鼠标按下事件
 * @param {*} evt 
 * @param {*} item 
 */
const handleMouseDown = (evt, item) => {

    if (evt.button !== 0) return; // 只处理主鼠标按钮（通常是左键）

    let currentItemRect = document.getElementById(item.id).getBoundingClientRect();

    // 计算并输出鼠标相对于组件的位置,暂存鼠标当前位置
    currentMouseLeft = evt.clientX - currentItemRect.left;
    currentMouseTop = evt.clientY - currentItemRect.top;
}


/**
 * @method
 * @desc 点击画布区域
 */
const handleClickEditPanel = () => {

    if (!storage.resizeTrigger) {
        emit("clearActiveItem");
        emit("handleResetSelectItem");
    }
    storage.resizeTrigger = false;
}

/**
 * @method
 * @param {String} id 当前组件的唯一标识符ID
 * @desc 清除其它中间组件的点击状态
 */
const clearOtherActive = (id) => {
    emit("clearOtherActive", id)
}

</script>

<style lang="less" scoped>
.designer-panel {
    width: 100%;
    height: calc(100vh - 50px);
    padding: 2px;
    overflow: hidden;
    padding: 30px;

    .designer-panel-body {
        // border: 1px solid red;
        width: 100%;
        height: 100%;
        overflow: auto;
        position: relative;
        margin: 0 auto;

        .active-box {
            // border: 1px dashed #3e8bf2;
            border: 1px dashed red;
            // background-color: rgba(62, 139, 242, 0.06);
            background-color: rgba(255, 0, 0, 0.3);
            position: absolute;
            pointer-events: none;
            transition: all 0.15s;

            // transition-property: all;
            // transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
            // transition-duration: 0.1s;
        }

        .edit-panel {
            width: 100%;
            height: 100%;
            display: block;
            cursor: pointer;
            transition: width 0.1s;
            overflow: auto;
            margin: 0 auto;
            border: 1px solid #e8e8e8;
            background-color: #fff;
            box-shadow: #0000001a 0 20px 25px -5px, #0000000a 0 10px 10px -5px;

            .component-wrap {
                position: relative;
            }
        }
    }
}
</style>